﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyMediaLite.RatingPrediction;
using MyMediaLite.Data;
using System.IO;
using System.Globalization;
using System.Diagnostics;

namespace recommenderSystem
{
    class MyParallelHybrid : RatingPredictor
    {
        SlopeOne slopy;
        UserKNNCosine knn;

        public override MyMediaLite.Data.IRatings Ratings
        {
            get
            {
                return base.Ratings;
            }
            set
            {
                base.Ratings = value;
                slopy.Ratings = value;
                knn.Ratings = value;
            }
        }

        public uint K
        {
            get
            {
                return knn.K;
            }
            set
            {
                knn.K = value;
            }
        }

        public MyParallelHybrid()
        {
            slopy = new SlopeOne();
            knn = new UserKNNCosine();
        }

        public override void Train()
        {
            slopy.Train();
            knn.Train();
        }

        public override double Predict(int user_id, int item_id)
        {
            var slopyPredict = slopy.Predict(user_id, item_id);
            var knnPredict = knn.Predict(user_id, item_id);

            // a combined predicted rating
            return (slopyPredict + knnPredict) * 0.5;
        }

        public Ratings WriteResultWithThreshold (double threshold, IRatings ratings, string filename)
        {
            Debug.WriteLine("MPH > starting ...");

            string line_format = "{0}\t{1}\t{2}";

            using (var writer = new StreamWriter(filename))
            {
                var user_mapping = new IdentityMapping();
                var item_mapping = new IdentityMapping();

                var resRatings = new Ratings();
                int userId, itemId;
                double predictedValues;

                for (int index = 0; index < ratings.Count; index++)
                {
                    userId = ratings.Users[index];
                    itemId = ratings.Items[index];
                    predictedValues = this.Predict(userId, itemId);

                    // only add values if predicted value is above threshold
                    
                    if (predictedValues >= threshold)
                    {
                        resRatings.Add(userId, itemId, predictedValues);

                        // save all to file
                        writer.WriteLine(
                            line_format,
                            user_mapping.ToOriginalID(userId),
                            item_mapping.ToOriginalID(itemId),
                            predictedValues.ToString(CultureInfo.InvariantCulture));
                    }
                }
                Debug.WriteLine("MPH > done");

                return resRatings;
            }
        }  
    }
}
